#include "dag.h"
#include "dag_types.h"

#include <memory>
#include <iostream>
#include <string.h>

using namespace dag;
using namespace std;

FrameSpec::FrameSpec()
:	bSize(0),
	iSize(0),
	fSize(0),
	dSize(0)
{
}

FrameSpec::FrameSpec(size_t numBools, size_t numInts, size_t numFloats, size_t numDoubles)
:	bSize(numBools),
	iSize(numInts),
	fSize(numFloats),
	dSize(numDoubles)
{}

bool FrameSpec::operator==(const FrameSpec& rhs) const {
	return (rhs.bSize == bSize &&
			rhs.iSize == iSize &&
			rhs.fSize == fSize &&
			rhs.dSize == dSize);
}

bool FrameSpec::operator!=(const FrameSpec& rhs) const {
	return !(*this == rhs);
}
	
void FrameSpec::serialize(ostream& binaryStream) const {
	binaryStream.write(dag_frame_spec_file_token, 
					   strlen(dag_frame_spec_file_token));
	dag_uint32_t numBools = bSize;
	dag_uint32_t numInts = iSize;
	dag_uint32_t numFloats = fSize;
	dag_uint32_t numDoubles = dSize;
	
	binaryStream.write((const char*)&numBools, dag_uint32_size);
	binaryStream.write((const char*)&numInts, dag_uint32_size);
	binaryStream.write((const char*)&numFloats, dag_uint32_size);
	binaryStream.write((const char*)&numDoubles, dag_uint32_size);
}

auto_ptr<FrameSpec> FrameSpec::inflate(istream& binaryStream) {
	auto_ptr<FrameSpec> fspec(new FrameSpec());
	fspec->load(binaryStream);
	return fspec;
}

void FrameSpec::load(istream& binaryStream) {
	char* header = NULL;
	bSize = 0;
	iSize = 0;
	fSize = 0;
	dSize = 0;
	
	try {
		/* check header in binary stream */
		size_t headerSize = strlen(dag_frame_spec_file_token);
		header = new char[headerSize + 1];
		memset(header, 0, headerSize + 1);
		
		binaryStream.read(header, strlen(dag_frame_spec_file_token));
		if (strcmp(header, dag_frame_spec_file_token) != 0) {
			throw InvalidToken(header, 
							   dag_frame_spec_file_token);
		}
		
		delete[] header;
		header = NULL;
		
		/* load values */
		dag_uint32_t numBools, numInts, numFloats, numDoubles;
		binaryStream.read((char*)&numBools, dag_uint32_size);
		binaryStream.read((char*)&numInts, dag_uint32_size);
		binaryStream.read((char*)&numFloats, dag_uint32_size);
		binaryStream.read((char*)&numDoubles, dag_uint32_size);
		
		bSize = numBools;
		iSize = numInts;
		fSize = numFloats;
		dSize = numDoubles;
	}
	catch (...) {
		delete[] header;
		header = NULL;
		throw;
	}
}